package org.carabiner.infinitest;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.StringTokenizer;

/**
 * 
 * @author <a href="mailto:benrady@gmail.com"Ben Rady</a>
 */
public class InfinitestUtils
{
  private static final String LINE_BREAK = "<br/>";

  public static String stackTraceToHTML(StackTraceElement[] stackTrace)
  {
    StringBuilder trace = new StringBuilder();
    trace.append("<html>");
    for (StackTraceElement element : stackTrace)
    {
      trace.append(element.toString() + LINE_BREAK);
    }
    trace.setLength(trace.length() - LINE_BREAK.length());
    trace.append("</html>");
    return trace.toString();
  }

  public static String throwableToString(Throwable throwable)
  {
    String lineSep = System.getProperty("line.separator");
    String stackTrace = throwable.getMessage();
    stackTrace = stackTrace + lineSep;
    stackTrace = stackTrace + stackTraceToString(throwable.getStackTrace());
    if (throwable.getCause() != null)
    {
      stackTrace = stackTrace + lineSep + "Caused By:" + lineSep;
      stackTrace = stackTrace + throwableToString(throwable.getCause());
    }
    return stackTrace;
  }

  public static String stackTraceToString(StackTraceElement[] stackTrace)
  {
    StringBuilder trace = new StringBuilder();
    String lineSep = System.getProperty("line.separator");
    for (StackTraceElement element : stackTrace)
    {
      trace.append(element.toString() + lineSep);
    }
    trace.setLength(trace.length() - lineSep.length());
    return trace.toString();
  }

  public static void touch(Class classToModify) throws IOException, InterruptedException
  {
    File file = getFileForClass(classToModify);
    InputStream inStream = new FileInputStream(file);
    ByteArrayOutputStream outStream = new ByteArrayOutputStream();
    copyStreams(inStream, outStream);
    outStream.flush();
    byte[] bytes = outStream.toByteArray();
    inStream = new ByteArrayInputStream(bytes);
    FileOutputStream foStream = new FileOutputStream(file, false);
    copyStreams(inStream, foStream);
    Thread.sleep(100);
  }

  public static void copyFile(File in, File out) throws Exception
  {
    if (!out.exists())
      out.createNewFile();
    if (!in.exists())
      throw new IllegalArgumentException(in + " does not exist");
    FileInputStream fis = new FileInputStream(in);
    FileOutputStream fos = new FileOutputStream(out);
    byte[] buf = new byte[1024];
    int i = 0;
    while ((i = fis.read(buf)) != -1)
    {
      fos.write(buf, 0, i);
    }
    fis.close();
    fos.close();
  }

  public static File getFileForClass(Class classToModify)
  {
    File file = getFileForClass(InfinitestSettings.getBuildPath(), classToModify);
    if (!file.exists())
      throw new IllegalArgumentException(file + " does not exist");
    return file;
  }

  public static File getFileForClass(File baseDir, Class classToModify)
  {
    String classname = classToModify.getName();
    classname = classname.replace(".", "/");
    File file = new File(baseDir + "/" + classname + ".class");
    return file;
  }

  public static void copyStreams(InputStream in, OutputStream out) throws IOException
  {
    // Transfer bytes from in to out
    byte[] buf = new byte[1024];
    int len;
    while ((len = in.read(buf)) > 0)
    {
      out.write(buf, 0, len);
    }
    in.close();
    out.flush();
    if (out instanceof FileOutputStream)
      ((FileOutputStream) out).getFD().sync();
    out.close();
  }

  public static String getCleanClasspath(String classpath)
  {
    StringTokenizer tokenizer = new StringTokenizer(classpath, File.pathSeparator);
    // HACK some classpath elements apparently cause the external process
    // to fail to start.
    String[] exclusions = { "QTJava.zip", "junit-3.8.1.jar" };
    String newClasspath = "";

    while (tokenizer.hasMoreElements())
    {
      String e = tokenizer.nextToken();
      boolean ignoreClasspathElement = false;
      for (String exclusion : exclusions)
      {
        ignoreClasspathElement = ignoreClasspathElement || e.contains(exclusion);
      }
      if (!ignoreClasspathElement)
        newClasspath += e + File.pathSeparator;
    }
    return newClasspath;
  }

  public static boolean move(File srcFile, File destFile) throws Exception
  {
    copyFile(srcFile, destFile);
    if (!srcFile.delete())
    {
      srcFile.deleteOnExit();
      return false;
    }
    return true;
  }
}
